package com.enba.mallapi.aop;

import com.alibaba.fastjson2.TypeReference;
import com.enba.boot.core.context.SecurityContextHolder;
import com.enba.boot.core.exception.AuthException;
import com.enba.mallapi.annotation.RequiresPermissions;
import com.enba.mallapi.annotation.RequiresPermissions.Logical;
import com.enba.mallapi.annotation.RequiresRoles;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class PreAuthorizeAspect {

  private static final String POINTCUT =
      "@annotation(com.enba.mallapi.annotation.RequiresPermissions) || "
          + "@annotation(com.enba.mallapi.annotation.RequiresRoles)";

  @Pointcut(POINTCUT)
  public void pointcut() {}

  @Around("pointcut()")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();

    // 角色校验或权限校验
    checkPerms(signature.getMethod());

    return joinPoint.proceed();
  }

  public void checkPerms(Method method) {
    // 角色校验
    RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class);
    if (requiresRoles != null) {
      // 接口需要的角色信息
      String needRole = requiresRoles.value();

      if (StringUtils.isNotBlank(needRole)) {
        // 从上下文获取用户拥有的角色信息
        Set<String> roleSet =
            SecurityContextHolder.getValue("role", new TypeReference<Set<String>>() {});

        if (!roleSet.contains(needRole)) {
          AuthException.throwEx();
        }
      }
    }

    // 权限校验
    RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
    if (requiresPermissions != null) {
      // 接口需要的权限信息
      String[] needPerms = requiresPermissions.value();

      if (needPerms.length > 0) {
        // 从上下文获取用户拥有的权限信息
        Set<String> permsSet =
            SecurityContextHolder.getValue("perms", new TypeReference<Set<String>>() {});

        if (requiresPermissions.logical() == Logical.AND) {
          // 必须满足所有权限
          if (!permsSet.containsAll(Arrays.asList(needPerms))) {
            AuthException.throwEx();
          }
        } else {
          // 满足任意权限
          if (Arrays.stream(needPerms).noneMatch(permsSet::contains)) {
            AuthException.throwEx();
          }
        }
      }
    }
  }
}
